﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Windows;
using System.Windows.Input;

namespace GraphDrawing
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow
    {
        Random _rnd;
        List<Vertex> _vertexList;
        List<Edge> _edgeList;

        bool _generated;
        bool _isActiveVertex;
        int _activeVertex;
        int _activeTree;
        int _numberOfTrees;
        private Tree _gt;
        private List<List<Edge>> _treesList;
        private List<List<Edge>> _isomorphismList;

        public MainWindow()
        {
            InitializeComponent(); 

            //inicjacja
            error1.Visibility = Visibility.Hidden; //Używaj tylko cyfr !
            error2.Visibility = Visibility.Visible; //p miedzy 0:1;

            //System.Windows.Controls.Panel.GetZIndex(drawingArea);

            backTreeButton.IsEnabled = false;
            nextTreeButton.IsEnabled = false;
        }

        //STARE RYSOWANIE
        //public void graphEdge(Point point)
        //{
        //    Ellipse circle = new Ellipse();
        //    circle.Width = 10;
        //    circle.Height = 10;
        //    circle.Fill = Brushes.Black;

        //    Canvas.SetLeft(circle, point.X);
        //    Canvas.SetTop(circle, point.Y);
        //    drawingArea.Children.Add(circle);
        //}

        private void NumbersOfEdgesPreviewTextInput(object sender, TextCompositionEventArgs e)
        {
            var valid = new NumberValidate(e.Text);

            if (!valid.isNumber())
            {
                error1.Visibility = Visibility.Visible;
                error1.Content = "Use only numbers !";
            }
            else error1.Visibility = Visibility.Hidden;

            e.Handled = !valid.isNumber();
            base.OnPreviewTextInput(e);
        }

        private void SolveGraphClick(object sender, RoutedEventArgs e)
        {
            
            _rnd = new Random();
            var numberOfInconsistentGraphs = 0;

            var maxX = drawingArea.ActualWidth - 50;
            var maxY = drawingArea.ActualHeight - 50;

            var numbersOfVertices = Convert.ToInt32(numbersOfEdges.Text);
            var numbersOfMaxEdges = ((numbersOfVertices) * (numbersOfVertices - 1) / (2));

            if (numbersOfVertices > 70)
            {
                error1.Content = "MAX 70 !";
                error1.Visibility = Visibility.Visible;

            }
            else
            {
                error1.Content = "Use only numbers !";
                error1.Visibility = Visibility.Hidden;

                labelNumberOfMaxEdges.Content = "Number of MAX edges: " + numbersOfMaxEdges;

                _edgeList = new List<Edge>();
                _vertexList = new List<Vertex>(numbersOfVertices);

                for (int i = 0; i < numbersOfVertices; i++)
                {
                    var point = new Point(_rnd.Next(10, (int)maxX), _rnd.Next(10, (int)maxY));
                    _vertexList.Add(new Vertex(10, 10, point));
                }

                //Jezeli wylosowana liczba jest z zakresu (0,1)
                if (Convert.ToDouble(pBox.Text) > 0 && Convert.ToDouble(pBox.Text) < 1)
                {
                    ValidateEdges validate;
                    do
                    {
                        _edgeList.Clear();

                        for (int i = 0; i < numbersOfVertices; i++)
                        {
                            for (int j = i + 1; j < numbersOfVertices; j++)
                            {
                                //edgeList.Add(new Edge(vertexList[i].possition, vertexList[j].possition));
                                if (Convert.ToDouble(pBox.Text) > _rnd.NextDouble())
                                {
                                    //edgeList.Add(new Edge(vertexList[i].possition, vertexList[j].possition));
                                    _edgeList.Add(new Edge(_vertexList, i, j));
                                }
                            }
                        }

                        validate = new ValidateEdges(_edgeList, _vertexList);
                        if (!validate.IsValid())
                        {
                            logBox.Text += "Generated graph was inconsistent ! : " + DateTime.Now + Environment.NewLine;
                            labelNumberOfInconsistentGraphs.Content = "Inconsistent graphs: " + (++numberOfInconsistentGraphs);
                        }

                    } while (!validate.IsValid());
                }
                else //Jezeli wpisana wartosc nalezy do wartosci brzegowych - jezeli 0 to wywoluje sie ostatnie 3 linie !
                {
                    if (Convert.ToDouble(pBox.Text) == 1)
                    {
                        for (int i = 0; i < numbersOfVertices; i++)
                        {
                            for (int j = i + 1; j < numbersOfVertices; j++)
                            {
                                //edgeList.Add(new Edge(vertexList[i].possition, vertexList[j].possition));
                                _edgeList.Add(new Edge(_vertexList, i, j));
                            }
                        }
                    }
                }
                labelNubmerOfEdges.Content = "Number of edges: " + _edgeList.Count;
                _generated = true;
                //Tree test = new Tree(_vertexList);
                StartDrawGraphClick(sender, e);
            }
        }

        private void StartDrawGraphClick(object sender, RoutedEventArgs e)
        {
            drawingArea.Children.Clear(); //Clear canvas

            if (isDisplayLines.IsChecked != null && (bool)isDisplayLines.IsChecked)
            {
                for (int i = 0; i < _edgeList.Count; i++)
                {
                    _edgeList[i].draw(drawingArea, isDisplayPositions.IsChecked != null && (bool)isDisplayPositions.IsChecked, i + 1);
                }
            }

            for (int i = 0; i < _vertexList.Count; i++)
            {
                _vertexList[i].draw(drawingArea, isDisplayPositions.IsChecked != null && (bool)isDisplayPositions.IsChecked, i+1);
            }
            
        }

        private void PBoxPreviewTextInput(object sender, TextCompositionEventArgs e)
        {
            //if (!(0 >= Convert.ToDouble(pBox.Text) && Convert.ToDouble(pBox.Text) <= 1))
            //{
            //    error2.Visibility = System.Windows.Visibility.Visible;
            //    error2.Content = "P must be [0:1] !";
            //}
            //else error2.Visibility = System.Windows.Visibility.Hidden;

            //e.Handled = !(0 >= Convert.ToDouble(pBox.Text) && Convert.ToDouble(pBox.Text) <= 1);
            //base.OnPreviewTextInput(e);
        }

        private void SaveAsXMLButtonClick(object sender, RoutedEventArgs e)
        {
            if (_generated)
            {
                try
                {
                    var save = new savegraphml();

                    var saveFileDialog = new Microsoft.Win32.SaveFileDialog {Filter = "XML Files(*.xml)|*.xml"};
                    saveFileDialog.ShowDialog();

                    save.savegraph(_vertexList, _edgeList, saveFileDialog.FileName);

                    logBox.Text += "Successfully saved as '" + saveFileDialog.SafeFileName + "' ! : " + DateTime.Now + Environment.NewLine;
                }
                catch (Exception ex)
                {
                    logBox.Text += "ERROR! : " + ex.Message + " : " + DateTime.Now + Environment.NewLine;
                }
            }
            else
            {
                logBox.Text += "Try to solve graph before you save it! : " + DateTime.Now + Environment.NewLine;
            }
        }

        private void ImportFromXMLButtonClick(object sender, RoutedEventArgs e)
        {
            try
            {
                var openFileDialog = new Microsoft.Win32.OpenFileDialog {Filter = "XML Files(*.xml)|*.xml"};
                var resault = openFileDialog.ShowDialog();

                if(resault == true)
                {
                    logBox.Text += "Graph imported successfully! : " + DateTime.Now + Environment.NewLine;
                } 

                //klasa + otwieranie

                var readFromXML = new readgraphml(openFileDialog.FileName, drawingArea);
                _vertexList = readFromXML.wierzcholki;
                _edgeList = readFromXML.krawedzie;

                var numbersOfVertices = _vertexList.Count;
                var numbersOfMaxEdges = ((numbersOfVertices) * (numbersOfVertices - 1) / (2));

                labelNumberOfMaxEdges.Content = "Number of MAX edges: " + numbersOfMaxEdges;
                labelNubmerOfEdges.Content = "Number of edges: " + _edgeList.Count;
                numbersOfEdges.Text = _edgeList.Count.ToString(CultureInfo.InvariantCulture);

                StartDrawGraphClick(sender, e);
            }
            catch (Exception ex)
            {
                logBox.Text += "ERROR! : " + ex.Message + " : " + DateTime.Now + Environment.NewLine;
            }
            
        }

        private void MenuItemClearClick(object sender, RoutedEventArgs e)
        {
            var resault = MessageBox.Show("Do you want to save logs ? ", "Clearing logs", MessageBoxButton.YesNoCancel, MessageBoxImage.Question);

            switch (resault)
            {
                case MessageBoxResult.Cancel:

                    break;
                case MessageBoxResult.No:
                    logBox.Text = "";
                    break;
                case MessageBoxResult.Yes:
                    MenuItemClick(sender, e);
                    logBox.Text = "";
                    break;
            }


        }

        private void MenuItemClick(object sender, RoutedEventArgs e)
        {
            try
            {
                var saveFileDialog = new Microsoft.Win32.SaveFileDialog {Filter = "Text file (*.txt)|*.txt"};
                saveFileDialog.ShowDialog();

                using (var sw = new System.IO.StreamWriter(saveFileDialog.FileName))
                {
                    sw.Write(logBox.Text);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
            
        }

        private void DrawingAreaPreviewMouseMove(object sender, MouseEventArgs e)
        {
           /*// System.Windows.Controls.Canvas.SetZIndex(drawingArea, 99);
            if (e.LeftButton == MouseButtonState.Pressed)
            {
                Point mouse = Mouse.GetPosition(drawingArea);

                for (int i = 0; i < vertexList.Count; i++)
                {
                    if ((mouse.X >= vertexList[i].possition.X - vertexList[i].GetWidth()) && ((mouse.X <= vertexList[i].possition.X + vertexList[i].GetWidth())))
                    {
                        if ((mouse.Y >= vertexList[i].possition.Y - vertexList[i].GetWidth()) && ((mouse.Y <= vertexList[i].possition.Y + vertexList[i].GetHeight())))
                        {
                            vertexList[i].possition = mouse;
                            //vertexList[i].SetBrushColor(System.Windows.Media.Brushes.OrangeRed);
                            startDrawGraph_Click(sender, e);
                            
                            
                        }
                    }
                }
                //System.Windows.Controls.Canvas.SetZIndex(drawingArea, zOrder);
            }         */
            if (e.LeftButton == MouseButtonState.Pressed && _isActiveVertex)
            {
                Point mouse = Mouse.GetPosition(drawingArea);
                _vertexList[_activeVertex].possition = mouse;
                StartDrawGraphClick(sender, e);
            }
        }

        private void DrawingAreaPreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e)
        {
            _isActiveVertex = false;
            _vertexList[_activeVertex].SetBrushColor(System.Windows.Media.Brushes.Black);
            StartDrawGraphClick(sender, e);
        }

        private void DrawingAreaPreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {

            if (!_isActiveVertex)
            {
                var mouse = Mouse.GetPosition(drawingArea);

                for (int i = 0; i < _vertexList.Count; i++)
                {
                    if ((mouse.X >= _vertexList[i].possition.X - _vertexList[i].GetWidth()) && ((mouse.X <= _vertexList[i].possition.X + _vertexList[i].GetWidth())))
                    {
                        if ((mouse.Y >= _vertexList[i].possition.Y - _vertexList[i].GetWidth()) && ((mouse.Y <= _vertexList[i].possition.Y + _vertexList[i].GetHeight())))
                        {
                            _isActiveVertex = true;
                            _activeVertex = i;
                            _vertexList[_activeVertex].SetBrushColor(System.Windows.Media.Brushes.OrangeRed);
                            StartDrawGraphClick(sender, e);
                        }
                    }
                }
            }
        }

        private void DrawTreesClick(object sender, RoutedEventArgs e)
        {

            if (Convert.ToInt32(numbersOfEdges.Text) > 3)
            {
                var resault = MessageBox.Show("This operation may take a long time.\n\n Are you sure you want it ? ", "Warrning !", MessageBoxButton.YesNoCancel, MessageBoxImage.Question);

                switch (resault)
                {
                    case MessageBoxResult.Cancel:

                        break;
                    case MessageBoxResult.No:
                        //logBox.Text = "";
                        break;
                    case MessageBoxResult.Yes:
                        {
                            _gt = new Tree(_vertexList);
                            _treesList = _gt.GetTrees();
                            DrawTree();
                        }
                        break;
                }
            }
            _gt = new Tree(_vertexList);
            _treesList = _gt.GetTrees();

            DrawTree();
        }

        private void NextTreeButtonClick(object sender, RoutedEventArgs e)
        {
            _activeTree++;
            labelNumberOfTrees.Content = (_activeTree + 1) + " / " + _numberOfTrees;
            //DrawTreesClick(sender, e);
            DrawTree();

            if ((_activeTree + 1) == _numberOfTrees)
            {
                nextTreeButton.IsEnabled = false;
            }
            if (_activeTree > 0)
            {
                backTreeButton.IsEnabled = true;
            }

            //drawingArea.InvalidateVisual();
            //drawingArea= listTrees[activeTree];
            
        }
        
        private void BackTreeButtonClick(object sender, RoutedEventArgs e)
        {
            _activeTree--;
            labelNumberOfTrees.Content = (_activeTree + 1) + " / " + _numberOfTrees;
            //DrawTreesClick(sender, e);
            DrawTree();

            if (_activeTree == 0)
            {
                backTreeButton.IsEnabled = false;
            }
            if ((_activeTree + 1) < _numberOfTrees)
            {
                nextTreeButton.IsEnabled = true;
            }
        }

        private void DrawTree()
        {
            
            _numberOfTrees = _treesList.Count;

            drawingArea.Children.Clear();
            for (int j = 0; j < (_treesList[_activeTree]).Count; j++)
            {
                (_treesList[_activeTree])[j].draw(drawingArea, isDisplayPositions.IsChecked != null && (bool)isDisplayPositions.IsChecked, j);

            }

            for (int g = 0; g < _vertexList.Count; g++)
            {
                _vertexList[g].draw(drawingArea, isDisplayPositions.IsChecked != null && (bool)isDisplayPositions.IsChecked, g + 1);
            }

            //listTrees.Add(drawingArea);
            //startDrawGraph_Click(sender, e);
            //Thread.Sleep(1000);

            //drawTrees_Click(sender, e);
            labelNumberOfTrees.Content = (_activeTree + 1) + " / " + _numberOfTrees;

            nextTreeButton.IsEnabled = true;
        }

        private void ButtonIsomorphismClick(object sender, RoutedEventArgs e)
        {
            var isomorphism = new izomorphizm();
            if (_treesList == null)
            {
                var resault = MessageBox.Show(
                    "To show You isomorphism need to generate trees first.\n\n Generate trees ?",
                    "Warrning !", MessageBoxButton.YesNoCancel, MessageBoxImage.Question);

                switch (resault)
                {
                    case MessageBoxResult.Cancel:

                        break;
                    case MessageBoxResult.No:
                        //logBox.Text = "";
                        break;
                    case MessageBoxResult.Yes:
                    {
                        _gt = new Tree(_vertexList);
                        _treesList = _gt.GetTrees();
                        _isomorphismList = isomorphism.FindIzomorphizm(_treesList);
                        DrawIsomorphism(0);
                    }
                    break;
                }
            }
            else
            {
               
                _isomorphismList = isomorphism.FindIzomorphizm(_treesList);
                DrawIsomorphism(1);
            }
        }

        private void DrawIsomorphism(int preview)
        {
            drawingArea.Children.Clear();

            if ((_isomorphismList != null) && (_isomorphismList.Count != 0))
            {
                for (int j = 0; j < (_isomorphismList[preview]).Count; j++)
                {
                    (_treesList[preview])[j].draw(drawingArea,
                                                  isDisplayPositions.IsChecked != null &&
                                                  (bool) isDisplayPositions.IsChecked, j);

                }

                for (int g = 0; g < _vertexList.Count; g++)
                {
                    _vertexList[g].draw(drawingArea,
                                        isDisplayPositions.IsChecked != null 
                                        && (bool) isDisplayPositions.IsChecked,
                                        g + 1);
                }
            }
            else
            {
                MessageBox.Show("Can't find any isomorphic trees !", "Info");
            }
        }

        private void ButtonIsomorphismTree1Click(object sender, RoutedEventArgs e)
        {
            DrawIsomorphism(0);
        }

        private void ButtonIsomorphismTree2Click(object sender, RoutedEventArgs e)
        {
            DrawIsomorphism(1);
        }
    }
}
